// Copyright (C) 2006 Taylor L. Riché <riche@cs.utexas.edu>
//  
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software 
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//

#include "Packet.hh"
#include "Eth_Packet.hh"
#include "TCP_Packet.hh"
#include "TCP6_Packet.hh"
#include "UDP_Packet.hh"
#include "UDP6_Packet.hh"
#include <boost/functional/hash.hpp>


using namespace pktTypes;

lagniappe::FlowID
Packet::getFiveTupleID()
{
  Eth_Packet eth(*this);
  IP_Packet ip(eth);
  TCP_Packet tcp(ip);
  lagniappe::FlowID hash = 0;
//   hash = ip.getSrcAddr() + ip.getDstAddr() + ip.getProt();
//   hash += tcp.getSrcPort() + tcp.getDstPort();
//   hash = CKSUM_CARRY(hash);
//   boost::hash<lagniappe::FlowID> h;
  
  boost::hash_combine(hash,ip.getSrcAddr());
  boost::hash_combine(hash,ip.getDstAddr());
  boost::hash_combine(hash,ip.getProt());
  boost::hash_combine(hash,tcp.getSrcPort());
  boost::hash_combine(hash,tcp.getDstPort());

  return hash;

}

lagniappe::FlowID 
Packet::getFiveTupleID(tt::FiveTuple & ft)
{
  lagniappe::FlowID hash = 0;
//   hash = ft.saddr + ft.daddr + ft.proto;
//   hash += ft.sport + ft.dport;
//   hash = CKSUM_CARRY(hash);
//   boost::hash<lagniappe::FlowID> h;
  
  boost::hash_combine(hash, ft.saddr);
  boost::hash_combine(hash, ft.daddr);
  boost::hash_combine(hash, ft.proto);
  boost::hash_combine(hash, ft.sport);
  boost::hash_combine(hash, ft.dport);

  return hash;
}


lagniappe::FlowID
Packet::getUDPFiveTupleID()
{
  IP_Packet ip(*this);
  UDP_Packet udp(ip);
  lagniappe::FlowID hash = 0;
//   hash = ip.getSrcAddr() + ip.getDstAddr() + ip.getProt();
//   hash += udp.getSrcPort() + udp.getDstPort();
//   hash = CKSUM_CARRY(hash);
  boost::hash_combine(hash,ip.getSrcAddr());
  boost::hash_combine(hash,ip.getDstAddr());
  boost::hash_combine(hash,ip.getProt());
  boost::hash_combine(hash,udp.getSrcPort());
  boost::hash_combine(hash,udp.getDstPort());
  return hash;

}

lagniappe::FlowID
Packet::getSixFiveTupleID()
{
  Eth_Packet eth(*this);
  IP6_Packet ip6(eth);
  TCP6_Packet tcp6(ip6);
  lagniappe::FlowID hash = 0;
//   sum = in_cksum((uint16_t *)&ip6.getSourceAddress().s6_addr16, 16);
//   sum += in_cksum((uint16_t *)&ip6.getDestinationAddress().s6_addr16, 16);
//   sum += tcp6.getSrcPort() + tcp6.getDstPort() + ip6.getNextHeader();
//   sum = CKSUM_CARRY(sum);

  boost::hash_combine(hash, in_cksum((uint16_t *)&ip6.getSourceAddress().s6_addr16, 16));
  boost::hash_combine(hash, in_cksum((uint16_t *)&ip6.getDestinationAddress().s6_addr16, 16));
  boost::hash_combine(hash, tcp6.getSrcPort());
  boost::hash_combine(hash, tcp6.getDstPort());
  boost::hash_combine(hash, ip6.getNextHeader());

  return hash;
}

lagniappe::FlowID
Packet::getUDPSixFiveTupleID()
{
  Eth_Packet eth(*this);
  IP6_Packet ip6(eth);
  UDP6_Packet udp6(ip6);
  lagniappe::FlowID hash = 0;
//   sum = in_cksum((uint16_t *)&ip6.getSourceAddress().s6_addr16, 16);
//   sum += in_cksum((uint16_t *)&ip6.getDestinationAddress().s6_addr16, 16);
//   sum += tcp6.getSrcPort() + tcp6.getDstPort() + ip6.getNextHeader();
//   sum = CKSUM_CARRY(sum);

  boost::hash_combine(hash, in_cksum((uint16_t *)&ip6.getSourceAddress().s6_addr16, 16));
  boost::hash_combine(hash, in_cksum((uint16_t *)&ip6.getDestinationAddress().s6_addr16, 16));
  boost::hash_combine(hash, udp6.getSrcPort());
  boost::hash_combine(hash, udp6.getDstPort());
  boost::hash_combine(hash, ip6.getNextHeader());

  return hash;
}
